//
//  SBPopoverViewController.m
//  MouseShaker
//
//  Created by LiuLichen on 2022/5/7.
//

#import "SBPopoverViewController.h"

@interface SBPopoverViewController ()

@property(weak) IBOutlet NSTextField* loopTimesTextField;
@property(weak) IBOutlet NSTextField* statusTextField;
@property(weak) IBOutlet NSTextField* moveDisTextField;
@property(weak) IBOutlet NSTextField* timeIntTextField;

@property (nonatomic, strong) NSTimer* timer;
@property (nonatomic) NSUInteger loopTimes;
@property (nonatomic) NSUInteger moveDis;
@property (nonatomic) NSTimeInterval timeInterval;
@property (nonatomic) NSDate* lastMovedDate;

@end

@implementation SBPopoverViewController

#pragma mark - overrides

- (void)viewDidLoad {
    [super viewDidLoad];

    self.loopTimes = 0;
    self.moveDis = 2;
    self.timeInterval = 10;
}

- (IBAction)quit:(NSButton*)sender {
    [[NSApplication sharedApplication] terminate:self];
}

#pragma mark - ui actions

- (IBAction)startShake:(NSButton*)sender {
    if ([self.timer isValid]) {
        NSLog(@"startShake timer already exists");
        NSAlert* alert = [[NSAlert alloc] init];
        [alert setMessageText:@"startShake timer already exists"];
        [alert runModal];
        return;
    }

    NSUInteger moveDisInput = [self.moveDisTextField.stringValue integerValue];
    NSUInteger timeIntInput = [self.timeIntTextField.stringValue integerValue];
    self.moveDis = moveDisInput == 0 ? self.moveDis : moveDisInput;
    self.timeInterval = timeIntInput == 0 ? self.timeInterval : timeIntInput;

    self.lastMovedDate = [NSDate date];
    self.timer = [NSTimer timerWithTimeInterval:self.timeInterval target:self selector:@selector(timerShake) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];

    [self updateStatusTextField];
}

- (IBAction)stopShake:(NSButton*)sender {
    if ([self.timer isValid]) {
        [self.timer invalidate];
    }
    self.loopTimes = 0;
    self.lastMovedDate = [NSDate date];

    [self updateLoopTimesTextField];
    [self updateStatusTextField];
}

#pragma mark - public interfaces

- (void) notifyMouseMoved {
//    NSLog(@"notifyMouseMoved");
    self.lastMovedDate = [NSDate date];
}

#pragma mark - private interfaces

/**
 * This method is called every self.timeInterval, and it starts when click the start button and stops when click the stop button. Things needed to do in it:
 * 1. get the current time and check the interval between it and self.lastMovedDate, start the auto-move-mouse if the interval is greater than self.timeInterval.
 */
- (void) timerShake {
    self.loopTimes++;
    if (self.loopTimes >= UINT_MAX) {
        self.loopTimes = 0;
    }

    NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:self.lastMovedDate];
    NSLog(@"interval = %f", interval);

    if (interval >= self.timeInterval) {
        [self createMouseEvent];
    } else {
        NSLog(@"timerShake interval less than timeInterval");
    }

    [self updateLoopTimesTextField];
}

- (void) createMouseEvent {
    CGEventRef locationEvent = CGEventCreate(NULL);
    CGPoint point = CGEventGetLocation(locationEvent);
    CGPoint nextPoint = self.loopTimes % 2 == 0 ? CGPointMake(point.x+self.moveDis, point.y+self.moveDis) : CGPointMake(point.x-self.moveDis, point.y-self.moveDis);
    CFRelease(locationEvent);

    NSLog(@"createMouseEvent loopTime = %lu, x = %f, y = %f", self.loopTimes, (float)nextPoint.x, (float)nextPoint.y);

    // Below two methods can only move mouse cursor's position, but cannot generate event messages, so cannot keep the status of Teams as Avaliable.
//    CGWarpMouseCursorPosition(nextPoint);
//    CGDisplayMoveCursorToPoint(CGMainDisplayID(), nextPoint);

    // CGEventPost need accessibility permission, so we need to grant the permission to it at the first time at the System Prefs -> Security & Privacy.
    CGEventRef moveEvent = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, nextPoint, kCGMouseButtonLeft);
    CGEventPost(kCGHIDEventTap, moveEvent);
    CFRelease(moveEvent);
}

- (void) updateLoopTimesTextField {
    [self.loopTimesTextField setStringValue:[[NSString alloc] initWithFormat:@"LoopTime: %lu", self.loopTimes]];
}

- (void) updateStatusTextField {
    NSString* statusText = [self.timer isValid] ? @"Status: Running" : @"Status: Stopped";
    [self.statusTextField setStringValue:statusText];
}

@end
